package com.cpi.cornpp.purchase.program.generator.action;

import java.util.ArrayList;
import java.util.Calendar;
import java.util.Collection;
import java.util.Collections;
import java.util.List;
import java.util.Locale;

import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import javax.servlet.http.HttpSession;

import org.apache.commons.lang.StringUtils;
import org.apache.struts.Globals;
import org.apache.struts.action.ActionForm;
import org.apache.struts.action.ActionForward;
import org.apache.struts.action.ActionMapping;
import org.apache.struts.actions.MappingDispatchAction;
import org.apache.struts.util.MessageResources;

import com.cpi.cornpp.biweek.comparator.BiWeekComparator;
import com.cpi.cornpp.biweeks.services.BiWeekService;
import com.cpi.cornpp.biweeks.view.BiWeekView;
import com.cpi.cornpp.biweeks.view.BiWeekViewList;
import com.cpi.cornpp.corntypes.services.CornTypesService;
import com.cpi.cornpp.plants.services.PlantService;
import com.cpi.cornpp.purchase.program.exception.PurchaseProgramException;
import com.cpi.cornpp.purchase.program.generator.form.PurchaseProgramGeneratorForm;
import com.cpi.cornpp.purchase.program.services.PurchaseProgramService;
import com.cpi.cornpp.purchase.program.view.PurchaseOrderChargeView;
import com.cpi.cornpp.purchase.program.view.PurchaseOrderView;
import com.cpi.cornpp.transports.exception.TransportException;
import com.cpi.cornpp.transports.service.TransportService;
import com.cpi.cornpp.transports.view.TransportChargeView;
import com.cpi.cornpp.transports.view.TransportView;
import com.cs.common.init.SystemParameterCollection;
import com.cs.common.init.beans.SystemParameterBean;

/**
 * 
 * Esta clase esta encargada del flujo de trabajo
 * para generar un programa de compra.
 * @author Administrador
 * @version 1.0 Fecha: 2-10-2009
 *
 */
public class PurchaseProgramGeneratorAction extends MappingDispatchAction{

	/** Identifier default workflow*/
	private static final String DEFAULT = "default";
	private static final String FAIL = "fail";
	/** */
	private final static String CUSTOM_EXCEPTION = "custom_exception";//$NON-NLS-1$
	private final static String ERROR_MESSAGE = "ERROR_MESSAGE";//$NON-NLS-1$
	private static final String ERROR_MESSAGE_LIST = "ERROR_MESSAGE_LIST";
	/** Identifier in the Request for info messages*/
	private static final String MESSAGE = "MESSAGE";
	/** Mensaje de insert*/
	private static final String RECORD_SAVED = "message.futurepurchase.record.save";
	private static final String PADDING_PARAMETER = "PADDING_FOR_CODE";

	/**
	 * 
	 * @param mapping
	 * @param form
	 * @param request
	 * @param response
	 * @return
	 * @throws Exception
	 */
	public ActionForward goAdd(ActionMapping mapping, ActionForm form,
			HttpServletRequest request, HttpServletResponse response)
			throws Exception{
		BiWeekService biWeekService = null;
		TransportService transportService = null;
		CornTypesService cornTypesService = null;
		PlantService plantService = null;
		
		BiWeekViewList biWeeks = null;
		List transports = null;
		List cornTypes;
		List plants = null;		
		PurchaseProgramGeneratorForm ppgForm = null;
		PurchaseOrderView view = null;		
		ppgForm = (PurchaseProgramGeneratorForm)form;
		ppgForm.setPurchaseOrderViews(new ArrayList(0));
		ppgForm.setTransportCharges(new ArrayList(0));
		
		view = new PurchaseOrderView();
		biWeekService = new BiWeekService();		
		biWeeks = biWeekService.getBiWeeks();
		Collections.sort(biWeeks, new BiWeekComparator());
		transportService = new TransportService();
		transports = transportService.getTransports();
		cornTypesService = new CornTypesService();
		cornTypes = cornTypesService.getListCornTypes();
		
		view.setBiWeekFinish(biWeeks.getFinishBiWeekDefaultId());
		view.setBiWeekInit(biWeeks.getInitBiWeekDefaultId());
		view.setCornTypeId("-1");
		plantService = new PlantService();
		plants = plantService.list();
		
		ppgForm = (PurchaseProgramGeneratorForm)form;
		ppgForm.setBiweeks(biWeeks);
		ppgForm.setTransports(transports);
		ppgForm.setPlants(plants);
		ppgForm.setCornTypes(cornTypes);
		ppgForm.setView(view);
		
	
		return mapping.findForward(DEFAULT);		
	}	
	
	/**
	 * Cargar costos y seleccionar el tipo de maiz para el transporte seleccionado
	 * @param mapping
	 * @param form
	 * @param request
	 * @param response
	 * @return
	 * @throws Exception
	 */
	public ActionForward loadCostForTransport(ActionMapping mapping, ActionForm form,
			HttpServletRequest request, HttpServletResponse response)
			throws Exception{
		PurchaseProgramGeneratorForm ppgForm = null;
		TransportService transportService = null;
		Collection transportCharges = null;
		int transportId ;
		TransportView transportView = null;
		
		ppgForm = (PurchaseProgramGeneratorForm)form;
		transportService = new TransportService();		
		transportId = Integer.valueOf(ppgForm.getView().getPurchaseOrderTransportId()).intValue();
		if(transportId != -1){
			transportCharges = transportService.getTransportChargesByTransport(Integer.valueOf(ppgForm.getView().getPurchaseOrderTransportId()).intValue());
			transportView = (TransportView)ppgForm.getTransports().get(ppgForm.getTransports().indexOf((new TransportView(transportId))));
			ppgForm.getView().setCornTypeId(String.valueOf(transportView.getCornTypesView().getCornTypeId()));
			ppgForm.setTransportCharges(transportCharges);
			
		}else{
			ppgForm.setTransportCharges(new ArrayList(0));
		}
		return mapping.findForward(DEFAULT);
	}
	
	/**
	 * 
	 * @param mapping
	 * @param form
	 * @param request
	 * @param response
	 * @return
	 * @throws Exception
	 */
	public ActionForward preGenerate(ActionMapping mapping, ActionForm form,
			HttpServletRequest request, HttpServletResponse response)
			throws Exception{
		PurchaseProgramGeneratorForm ppgForm = null;
		PurchaseOrderView view = null; 
		TransportView transportView = null;
		int transportId = 0;
		int indexTransport = 0;
		int numOfBiWeeks = 0;
		int indexBiWeekInit = 0;
		int indexBiWeekFinish = 0;
		int numPurchaseOrders = 0;
		int startWith = 0;
		int indexIncrement = 0;
		int indexCode = 0;
		List biWeeks = null;
		List transportCharges = null;
		List pos = null;
		BiWeekView biWeekInit = null;
		BiWeekView biWeekFinish = null;
		List biweeksRange = null;
		ActionForward forward = null;
		HttpSession session = null;
		ArrayList errorList = null;
		
		
		
		session = request.getSession(false);
		messages = getResources(request);
		ppgForm = (PurchaseProgramGeneratorForm)form;
		view = ppgForm.getView();
		
		try{
			biWeeks = ppgForm.getBiweeks();
			indexBiWeekInit = biWeeks.indexOf(new BiWeekView(view.getBiWeekInit()));
			indexBiWeekFinish = biWeeks.indexOf(new BiWeekView(view.getBiWeekFinish()));
			biWeekInit = (BiWeekView)biWeeks.get(indexBiWeekInit);
			biWeekFinish= (BiWeekView)biWeeks.get(indexBiWeekFinish);
			
			errorList = validateForm(ppgForm,request, biWeekInit, biWeekFinish);		
			
			if(errorList.size()>0){
				session.setAttribute(ERROR_MESSAGE_LIST, errorList);
				return mapping.findForward(FAIL);
			}
			
			forward = mapping.findForward(DEFAULT);
			transportId = Integer.valueOf(view.getPurchaseOrderTransportId()).intValue();
		
			transportView = new TransportView();
			transportView.setTransportIdentifier(transportId);
			indexTransport = ppgForm.getTransports().indexOf(transportView);
			transportView = (TransportView)ppgForm.getTransports().get(indexTransport);
					
			numOfBiWeeks = getBiweeksBetween(biWeekInit, biWeekFinish);
			
			transportCharges = (ArrayList)ppgForm.getTransportCharges();
			
			numPurchaseOrders = numOfBiWeeks * view.getPurchaseOrderPeriodicity();		
			startWith = view.getStartWith();
			
			SystemParameterBean param = (SystemParameterBean)SystemParameterCollection.getInstance().get(PADDING_PARAMETER);
			pos = new ArrayList(0);
			indexIncrement = indexBiWeekInit;
			indexCode = startWith;
			for(int i = 1; i < numPurchaseOrders+1; i ++, startWith++, indexCode++){
				BiWeekView biWeekView = ((BiWeekView)biWeeks.get(indexIncrement));
				if( view.getTypeEnableWeek() == 0 || biWeekView.getBiweek() == view.getTypeEnableWeek()){
					String postFix = StringUtils.leftPad(String.valueOf(indexCode).trim(),param.getIntValue(),'0'); 
					PurchaseOrderView po = new PurchaseOrderView();
					po.setPurchaseOrderCode( transportView.getTransportNomenclature());
					po.setPostFix(postFix);
					po.setPurchaseOrderPlantId(view.getPurchaseOrderPlantId());
					po.setPurchaseOrderTransportId(String.valueOf(transportView.getTransportIdentifier()));
					
					po.setBiWeekInit(biWeekView.getBiweekPeriodId());
					po.setPurchaseOrderWeekPeriodId(String.valueOf(indexIncrement));
	
					if(i % view.getPurchaseOrderPeriodicity() == 0){
						indexIncrement = indexIncrement + 1;
					}
	
					if(transportCharges!=null){
						for(int j = 0; j < transportCharges.size(); j++){
							TransportChargeView tcv = (TransportChargeView)transportCharges.get(j);
							PurchaseOrderChargeView pocv = new PurchaseOrderChargeView();
							pocv.setPurchaseOrderAmount(tcv.getTransportChargeAmount());
							pocv.setPurchaseOrderChargeTypeId(String.valueOf(tcv.getTransportChargeTypeId()));						
							po.getPurchaseOrderCosts().add(pocv);
						}					
					}
					pos.add(po);
				}else{
					indexIncrement = indexIncrement + 1;
					indexCode = indexCode - 1;
				}
			}
			ppgForm.setPurchaseOrderViews(pos);
			biweeksRange = ppgForm.getBiweeks().subList(indexBiWeekInit, indexBiWeekFinish + 1);
			ppgForm.setBiweeksRange(biweeksRange);			
			forward = mapping.findForward(DEFAULT);
		} catch(Exception e){
			PurchaseProgramException ppe = new PurchaseProgramException(e , TransportException.LAYER_ACTION, TransportException.ACTION_LISTS);;
			
			session.setAttribute(CUSTOM_EXCEPTION, ppe);
			form.reset(mapping, request);
			e.printStackTrace(System.out);
			
			throw ppe;
		}	
		return forward;
	}

	
	/**
	 * Numero de biweeks entre el biweek de inicio y el biweek
	 * final indicados, se incluyen tambien dichos extremos.
	 * @param init
	 * @param finish
	 * @return Numero de biweeks entre los biweeks especificados 
	 */
	private int getBiweeksBetween(BiWeekView init, BiWeekView finish){
		int numOfMonths = 0;
		int numOfBiWeeks = 0;
		Calendar initCal = Calendar.getInstance();
		Calendar finishCal = Calendar.getInstance();
		
		initCal.set(Calendar.MONTH, init.getMonth()-1);
		initCal.set(Calendar.YEAR, init.getYear());
		
		finishCal.set(Calendar.MONTH, finish.getMonth()-1);
		finishCal.set(Calendar.YEAR, finish.getYear());
		
		numOfMonths = (int)finishCal.get(Calendar.MONTH) - initCal.get(Calendar.MONTH) + 1;
		numOfBiWeeks = (numOfMonths * 2) - ((2 - ( init.getBiweek() == 2 ? 1 : 2 )) + (2 - finish.getBiweek()));
		
		return numOfBiWeeks;		
	}
	
	/**
	 * 
	 * 
	 */
	public ActionForward add(ActionMapping mapping, ActionForm form,
			HttpServletRequest request, HttpServletResponse response)	throws Exception{
		
		PurchaseProgramGeneratorForm ppgForm = null;
		MessageResources messageResources = null;
		String messageError = null;
		PurchaseOrderView view = null;
		TransportView transportView = null;
		PurchaseProgramService service = null;
		TransportService transportService = null;
		HttpSession session = null;
		ActionForward forward = null;
		
		service = new PurchaseProgramService();
		transportService = new TransportService();
		ppgForm = (PurchaseProgramGeneratorForm)form;
		session = request.getSession(false);
		messageResources = getResources(request);
		forward = mapping.findForward(FAIL);
		
		view = ppgForm.getView();
		try{
			
			for(int i = 0; i < ppgForm.getPurchaseOrderViews().size(); i++){
				view = (PurchaseOrderView)ppgForm.getPurchaseOrderViews().get(i);
				transportView = transportService.getTransport(Integer.parseInt(view.getPurchaseOrderTransportId()));
				
				view.setPurchaseOrderCapacity(transportView.getTransportCapacity());
				
				if ("-1".equalsIgnoreCase(view.getPurchaseOrderPlantId())){
					view.setPurchaseOrderPlantId(null);
				}
				view.setCornTypeId(ppgForm.getView().getCornTypeId());
				service.addPurchaseOrder(view,true);
			}		
			forward = mapping.findForward(DEFAULT);
			
		} catch(PurchaseProgramException p){
			messageError = messageResources.getMessage((Locale)session.getAttribute(Globals.LOCALE_KEY), p.getErrorCode());
			
			if(null == messageError){
				PurchaseProgramException ppe = new PurchaseProgramException(p, PurchaseProgramException.LAYER_ACTION, PurchaseProgramException.ACTION_LISTS);
				session.setAttribute(CUSTOM_EXCEPTION, ppe);
				form.reset(mapping, request);
				throw ppe;
			}else{
				session.setAttribute(ERROR_MESSAGE, messageError);
				forward = mapping.findForward(FAIL);
			}
		} catch(Exception e){
			PurchaseProgramException ppe = new PurchaseProgramException(e , TransportException.LAYER_ACTION, TransportException.ACTION_LISTS);;
			
			session.setAttribute(CUSTOM_EXCEPTION, ppe);
			form.reset(mapping, request);
			e.printStackTrace(System.out);
			
			throw ppe;
		}		
		request.getSession(false).setAttribute(MESSAGE, messageResources.getMessage((Locale)session.getAttribute(Globals.LOCALE_KEY), RECORD_SAVED));
		ppgForm.setPurchaseOrderViews(new ArrayList(0));
		ppgForm.setTransportCharges(new ArrayList(0));
		return forward;
	}
	
	/**
	 * 
	 * @param ppgForm
	 * @param request
	 * @return
	 */
	private ArrayList validateForm(PurchaseProgramGeneratorForm ppgForm, HttpServletRequest request, BiWeekView init, BiWeekView finish) {
		ArrayList errors = new ArrayList(0);
		MessageResources messageResources = null;
		HttpSession httpSession = null;
		httpSession = request.getSession();
		messageResources = getResources(request);
		
		if(ppgForm.getView().getPurchaseOrderPeriodicity()==0){
			//errors.add(messageResources.getMessage("label"));
			errors.add(messageResources.getMessage((Locale)httpSession.getAttribute(Globals.LOCALE_KEY), "error.message.purchaseorder.wrong.periodicity"));
		}
		if(ppgForm.getView().getStartWith()==0){
			errors.add(messageResources.getMessage((Locale)httpSession.getAttribute(Globals.LOCALE_KEY), "error.message.purchaseorder.wrong.start"));			
		}
		if(ppgForm.getView().getPurchaseOrderTransportId().equals("-1")){
			errors.add(messageResources.getMessage((Locale)httpSession.getAttribute(Globals.LOCALE_KEY), "error.message.purchaseorder.select.tranport"));			
		}
		if(ppgForm.getView().getBiWeekInit()==-1){
			errors.add(messageResources.getMessage((Locale)httpSession.getAttribute(Globals.LOCALE_KEY), "error.message.purchaseorder.select.start.date"));			
		}
		if(ppgForm.getView().getBiWeekFinish()==-1){
			errors.add(messageResources.getMessage((Locale)httpSession.getAttribute(Globals.LOCALE_KEY), "error.message.purchaseorder.select.final.date"));			
		}
		if((init.getYear() > finish.getYear())){
			errors.add(messageResources.getMessage((Locale)httpSession.getAttribute(Globals.LOCALE_KEY), "error.message.purchaseorder.wrong.start.final.date"));						
		}else if((init.getYear() == finish.getYear())){
			if(init.getMonth() > finish.getMonth()){
				errors.add(messageResources.getMessage((Locale)httpSession.getAttribute(Globals.LOCALE_KEY), "error.message.purchaseorder.wrong.start.final.date"));
			}else if(init.getMonth() == finish.getMonth() && init.getBiweek() > finish.getBiweek()){
				errors.add(messageResources.getMessage((Locale)httpSession.getAttribute(Globals.LOCALE_KEY), "error.message.purchaseorder.wrong.start.final.date"));
			}
		}
		if(ppgForm.getTransportCharges()!=null){	
			for(int i = 0; i < ppgForm.getTransportCharges().size(); i++){
				TransportChargeView tcv = (TransportChargeView)((ArrayList)ppgForm.getTransportCharges()).get(i);
				if(!(tcv.getTransportChargeAmount()>0)){
					errors.add(messageResources.getMessage((Locale)httpSession.getAttribute(Globals.LOCALE_KEY), "warning.message.purchaseorder.invalid.pricePerTon"));
					
					break;
				}
			}
		}
		return errors;
		
	}
	
}
